﻿#pragma once

#include <mutex>
#include <vector>

#include "libdaq/device/base_device.h"
#include "libdaq/device/base_device_config.h"

namespace libdaq {
namespace device {
#define DAQ216_USB_VENDOR_ID 0x1A86
#define DAQ216_USB_PRODUCT_ID 0x5537
#define DAQ216_USB_END_POINT_IN {0x81}
#define DAQ216_USB_END_POINT_OUT {0x01}
class DAQ216 : public LockzhinerBaseDevice {
public:
  DAQ216();
  ~DAQ216() override;
  bool InitializeDevice() override;
  bool ConnectedDevice() override;
  bool DisconnectedDevice() override;

  bool BasicInfoGetDeviceType() override;
  bool BasicInfoGetHardwareVersion() override;
  bool BasicInfoGetBootLoaderVersion() override;
  bool BasicInfoGetSoftwareVersion() override;
  static backend::USBOption GetUSBOption() { return libdaq::backend::USBOption(DAQ216_USB_VENDOR_ID, DAQ216_USB_PRODUCT_ID, DAQ216_USB_END_POINT_IN, DAQ216_USB_END_POINT_OUT); }

  bool SendCommand(uint16_t command, const std::vector<uint8_t> &data) override;
  bool ConfigADCSampleRate(LockzhinerADCSampleRate sample_rate) override;
  bool ConfigADCVoltage(const std::vector<LockzhinerADCVoltage> &range_vector) override;
  bool ConfigADCVoltage(const LockzhinerADCVoltage &voltage) override;
  bool ConfigADCTrigger(LockzhinerADCTriggerType type,
                        LockzhinerADCTriggerMode mode,
                        LockzhinerADCChannel channel,
                        int level) override;
  bool ConfigADCTriggerLength(uint32_t data_length) override;
  bool ConfigTriggerTimeout(uint32_t timeout) override;

  bool ConfigADCChannel(uint8_t channel) override;
  bool ConfigADCChannel(const std::vector<bool> &channel_enable_list) override;
  bool ConfigADCTriggerSource(uint8_t source) override;
  bool ConfigACDC(uint8_t channel) override;

  bool StartADCCollection() override;
  bool StopADCCollection() override;
  bool ForceStopADCCollection() override;

  virtual bool UpgradeFirmware();
  virtual bool FirmwareInfo(uint32_t firmware_size);
  virtual bool SendFirmwareData(std::vector<uint8_t>& send_data);
  virtual bool CancelUpgradeFirmware(); // 取消更新固件
  bool SystemOpEraseFirmware() override;

  bool BasicInfoSetHardwareVersion(const std::vector<uint8_t>& data) override;

  bool ConfigCalibration(const std::vector<uint8_t> &data) override;
  bool ConfigOffsetCalibrationX1(const std::vector<uint8_t> &state) override;
  bool ConfigGetOffsetCalibrationX1(std::vector<uint16_t>& state) override;
  bool ConfigSaveOffsetCalibrationX1(const std::vector<uint8_t> &state) override;
  bool ConfigOffsetCalibrationX10(const std::vector<uint8_t> &state) override;
  bool ConfigGetOffsetCalibrationX10(std::vector<uint16_t>& state) override;
  bool ConfigSaveOffsetCalibrationX10(const std::vector<uint8_t> &state) override;
  bool ConfigGainCalibrationX1(const std::vector<uint8_t> &state) override;
  bool ConfigGetGainCalibrationX1(std::vector<uint16_t>& state) override;
  bool ConfigSaveGainCalibrationX1(const std::vector<uint8_t> &state) override;
  bool ConfigGainCalibrationX10(const std::vector<uint8_t> &state) override;
  bool ConfigGetGainCalibrationX10(std::vector<uint16_t>& state) override;
  bool ConfigSaveGainCalibrationX10(const std::vector<uint8_t> &channel) override;
  virtual bool OpenOffsetCalibrationX1(std::vector<uint8_t> &data);
  virtual bool OpenOffsetCalibrationX10(std::vector<uint8_t> &data);
  virtual bool OpenGainCalibrationX1(std::vector<uint8_t> &data);
  virtual bool OpenGainCalibrationX10(std::vector<uint8_t> &data);
  bool CloseCalibration() override;

  bool SystemOpResetFPGA() override;
  bool SystemOpRestoreFactoryConfig() override;
  bool SystemOpSetDeviceAddr(const uint8_t device_addr) override;
  bool SystemOpGetDeviceAddr(uint8_t& device_addr) override;
  bool SystemOpGetDeviceName(std::string& name) override;
  bool SystemOpSetDeviceName(const std::string& name) override;
  bool SystemOpGetMacAddr(std::vector<uint8_t>& mac_address) override;
  bool SystemOpSetMacAddr(const std::vector<uint8_t>& mac_address) override;
  bool SystemOpGetDeviceNetInfo(std::vector<uint8_t>& ip, std::vector<uint8_t>& netmask, std::vector<uint8_t>& broadcast) override;
  bool SystemOpSetDeviceNetInfo(const std::vector<uint8_t>& ip, const std::vector<uint8_t>& netmask, const std::vector<uint8_t>& broadcast) override;
  bool SystemOpGetServerInfo(std::vector<uint8_t>& ip, uint32_t& port) override;
  bool SystemOpSetServerInfo(const std::vector<uint8_t>& ip, const uint32_t& port) override;

  bool ProductTestGetDefaultConfig(std::vector<uint8_t>& config) override;
  bool ProductTestSetSN(const std::vector<uint8_t>& sn) override;
  bool ProductTestGetSN() override;
  bool ProductTestGetEepromUID(std::vector<uint8_t>& uid) override;
  bool ProductTestSetEepromUIDVerify(uint8_t enable) override;

  void SetDeviceInfoCallback(const DeviceInfoCallback& callback) override;

protected:
  virtual bool RecvConnectDeviceFunc(uint8_t* str);
  bool RecvGetDeviceTypeFunc(uint8_t* str);
  bool RecvGetHardwareVersionFunc(uint8_t* str);
  bool RecvGetBootLoaderVersionFunc(uint8_t* str);
  bool RecvGetSoftwareVersionFunc(uint8_t* str);
  bool RecvGetDeviceAddrFunc(uint8_t* str);
  bool RecvGetDeviceName(uint8_t* str);
  bool RecvGetDeviceNetInfo(uint8_t* str);
  bool RecvGetServerInfo(uint8_t* str);
  bool RecvGetDefaultConfig(uint8_t* str);
  bool RecvGetSN(uint8_t* str);
  bool RecvGetEepromUID(uint8_t* str);
  bool RecvGetMacAddr(uint8_t* str);
  bool RecvGetOffsetCalibrationX1(uint8_t* str);
  bool RecvGetOffsetCalibrationX10(uint8_t* str);
  bool RecvGetGainCalibrationX1(uint8_t* str);
  bool RecvGetGainCalibrationX10(uint8_t* str);

  bool RecvSendFirmwareData(uint8_t* str);
  bool RecvUpgradeFirmware(uint8_t* str);
  bool RecvFirmwareInfo(uint8_t* str);

protected:
  /******************** 1 命令发送相关 *********************/
  bool SendConnected() override;
  bool SendEnableDC(uint8_t channel) override;
  virtual bool SendSaveOffsetCalibrationX1(const std::vector<uint8_t> &state); // 保存偏移校正x1档
  virtual bool SendSaveOffsetCalibrationX10(const std::vector<uint8_t> &state); // 保存偏移校正x10档
  virtual bool SendSaveGainCalibrationX1(const std::vector<uint8_t> &state); // 保存增益校正x1档
  virtual bool SendSaveGainCalibrationX10(const std::vector<uint8_t> &state); // 保存增益校正x10档
  bool SendConfigTrigger(LockzhinerADCTriggerType type,
                         LockzhinerADCTriggerMode mode,
                         LockzhinerADCChannel channel,
                         int level) override; // 设置触发方式、触发模式、触发通道
  /******************** 1 命令发送相关 *********************/

  /******************** 2 接受发送数据线程相关 *********************/
  /********** 2.1 接受发送数据线程同步 **********/
  std::mutex mtx_; // 创建一个raw_data全局互斥锁，发送和读取只能同时进行一个内容
  std::condition_variable parse_thread_cond_; // 为了防止CPU占用过高，使用条件信号来缓解
  std::mutex parse_thread_mutex_; // 为了防止CPU占用过高，使用条件信号来缓解
  bool OpenReceiveAndParseThread();
  /********** 2.1 接受发送数据线程同步 **********/

  /********** 2.2 接受数据线程 **********/
  virtual bool ReadDataFromBackend(int timeout); // 从后端读取数据
  void PrintRawDataBuffer(const std::vector<unsigned char> &temp_parse_buffer);
  bool ReadRawDataFromBuffer(std::vector<unsigned char> &temp_parse_buffer, size_t need_read_size);
  void ReceiveThreadFunction(); // 接受数据线程执行函数
  /********** 2.2 接受数据线程 **********/

  /********** 2.3 解析数据线程 **********/
  /********** 2.3.1 解析数据包通用 **********/
  int receive_packet_index_ = 0; // 接收到的包序号
  bool PacketHeaderIsRight(std::vector<unsigned char> &temp_parse_buffer,
                           std::vector<unsigned char>::iterator &header_it); // 校验数据包头
  bool PacketTailIsRight(std::vector<unsigned char> &temp_parse_buffer,
                         std::vector<unsigned char>::iterator &tail_it); // 校验数据包尾
  void ParseThreadFunction(); // 解析数据线程执行函数

  bool ParseCommandPacket(std::vector<unsigned char> &temp_parse_buffer, unsigned char &packet_index) override; // 解析命令包
  bool ParseDataPacket(std::vector<unsigned char> &temp_parse_buffer, unsigned char &packet_index) override;
  bool ParsePacket(std::vector<unsigned char> &temp_parse_buffer,
                   unsigned char &command_packet_index,
                   unsigned char &data_packet_index); // 解析原始数据包
  bool IdentifyAndParsePacket(std::vector<unsigned char> &temp_parse_buffer,
                              unsigned char &command_packet_index,
                              unsigned char &data_packet_index); // 识别包类型并解析

  /********** 2.3 解析数据线程 **********/
  /******************** 2 接受发送数据线程相关 *********************/
  static const int PACKET_DATA_SIZE = 12;//12或者984
};
} // namespace device
} // namespace libdaq
